package io.gitee.hefren.hhconfig.client.repository.impl;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.reflect.TypeToken;
import io.gitee.hefren.hhconfig.client.beans.Configs;
import io.gitee.hefren.hhconfig.client.beans.ConfigsMeta;
import io.gitee.hefren.hhconfig.client.repository.HhConfigRepository;
import io.gitee.hefren.hhconfig.client.service.ChangeEvent;
import io.gitee.hefren.hhconfig.client.service.ChangeListener;
import io.gitee.hefren.hhconfig.client.service.HhConfigService;
import io.gitee.hefren.utils.http.HttpInvoker;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Date 2024/6/1
 * @Author lifei
 */
public class HhConfigRepositoryImpl implements HhConfigRepository {

    private final ConfigsMeta configsMeta;
//    private final ScheduledExecutorService executor;
    private final Map<String, Long> VERSIONS = Maps.newHashMap();
    private final Map<String, Map<String, String>> CONFIGS = Maps.newHashMap();
    private final List<ChangeListener> changeListenerList = Lists.newArrayList();

    public HhConfigRepositoryImpl(ConfigsMeta configsMeta) {
        this.configsMeta = configsMeta;
//        this.executor = Executors.newSingleThreadScheduledExecutor();
//        this.executor.scheduleWithFixedDelay(this::heartbeat, 1000, 10000, TimeUnit.MILLISECONDS);
        Thread deferredResultThread = new Thread(this::deferredResultHeartbeat);
        deferredResultThread.setDaemon(true);
        deferredResultThread.start();
    }

    @Override
    public Map<String, String> findConfigs() {
        String key = configsMeta.genKey();
        if (CONFIGS.containsKey(key)) {
            return CONFIGS.get(key);
        }
        return findAllConfigs();
    }

    @Override
    public void addChangeListener(ChangeListener changeListener) {
        if (Objects.nonNull(changeListener)) {
            this.changeListenerList.add(changeListener);
        }
    }

    private Map<String, String> findAllConfigs() {
        String url = configsMeta.listPath();
        TypeToken<List<Configs>> typeToken = new TypeToken<List<Configs>>() {};
        List<Configs> configs = HttpInvoker.httpGet(url, typeToken);
        Map<String, String> result = Maps.newHashMap();
        for (Configs config : configs) {
            result.put(config.getCkey(), config.getCvalue());
        }
        return result;
    }

    private void heartbeat() {
        String url = configsMeta.versionPath();
        Long newVersion = HttpInvoker.httpGet(url, Long.class);
        String key = Strings.lenientFormat("%s_%s_%s", configsMeta.getApp(), configsMeta.getEnv(), configsMeta.getNamespace());
        Long oldVersion = VERSIONS.getOrDefault(key, -1L);
        if (newVersion>oldVersion) {
            System.out.println("===> [hhconfig] old version: " + oldVersion + " new version: " + newVersion);
            Map<String, String> configs = findAllConfigs();
            CONFIGS.put(key, configs);
            VERSIONS.put(key, newVersion);
            System.out.println("===> [hhconfig] fire update all configs");
            changeListenerList.forEach(listener->listener.listener(new ChangeEvent(configsMeta, configs)));
        }
    }

    private void deferredResultHeartbeat() {
        while (true) {
            try {
                String url = configsMeta.deferredResultVersionPath();
                // 注意： 让 DeferredResult 的超时时间小于 HttpInvoker 的超时时间
                Long newVersion = HttpInvoker.httpGet(url, Long.class);
                String key = Strings.lenientFormat("%s_%s_%s", configsMeta.getApp(), configsMeta.getEnv(), configsMeta.getNamespace());
                Long oldVersion = VERSIONS.getOrDefault(key, -1L);
                if (newVersion>oldVersion) {
                    System.out.println("===> [hhconfig] deferredResultHeartbeat old version: " + oldVersion + " new version: " + newVersion);
                    Map<String, String> configs = findAllConfigs();
                    CONFIGS.put(key, configs);
                    VERSIONS.put(key, newVersion);
                    System.out.println("===> [hhconfig] deferredResultHeartbeat fire update all configs");
                    changeListenerList.forEach(listener->listener.listener(new ChangeEvent(configsMeta, configs)));
                }
            }catch (Exception e) {
                System.out.println("====> deferredResultHeartbeat exception: " + e.getMessage());
            }
        }

    }


}
